/*
 * Copyright (C), 2002-2017, 苏宁易购电子商务有限公司
 * FileName: SendCouponServiceImpl
 * Author:   15030469 胡丹
 * Date:     2017/5/2 14:33
 * Description: //模块目的、功能描述      
 * History: //修改记录
 * <author>      <time>      <version>    <desc>
 * 修改人姓名             修改时间            版本号                  描述
 */
package com.suning.sawp.service.impl.exchange;

import java.math.BigDecimal;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.google.common.base.Function;
import com.google.common.collect.Lists;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.suning.ebuy.spes.nonshoppingexecute.dto.freecoupon.FreeCouponReceiveInputDto;
import com.suning.ebuy.spes.nonshoppingexecute.dto.freecoupon.FreeCouponReceiveOutputDto;
import com.suning.ebuy.spes.nonshoppingexecute.service.FreeCouponReceiveReqService;
import com.suning.rsc.dto.responsedto.MbfResponse;
import com.suning.rsc.httpservice.annotation.EsbEIHttpWired;
import com.suning.rsf.spring.Reference;
import com.suning.sawp.constants.CacheKeyConstants;
import com.suning.sawp.constants.ConfigConstants;
import com.suning.sawp.constants.ExchangeConstants;
import com.suning.sawp.constants.PromotionConstants;
import com.suning.sawp.dto.common.ReturnMsg;
import com.suning.sawp.dto.esb.CouponRuleQueryReq;
import com.suning.sawp.dto.esb.LocateMemberInfo;
import com.suning.sawp.dto.esb.QryActDetailRsp.ActivityDetail;
import com.suning.sawp.dto.exchange.CouponDetailInfoDto;
import com.suning.sawp.dto.exchange.CouponRecordDto;
import com.suning.sawp.dto.exchange.QueryCouponDetailInfoFromSPESEsbDto;
import com.suning.sawp.dto.exchange.SendCouponRecordDto;
import com.suning.sawp.dto.mainpush.StoreManDto;
import com.suning.sawp.exception.SawpException;
import com.suning.sawp.intf.dao.exchange.ExchangeCouponRecordDao;
import com.suning.sawp.intf.dao.exchange.ExchangeOrderDao;
import com.suning.sawp.intf.esb.CouponRuleQueryEsbService;
import com.suning.sawp.intf.esb.MemberInfoService;
import com.suning.sawp.intf.exchange.ExchangeOrderCouponListQueryService;
import com.suning.sawp.intf.exchange.ExchangeOrderSendCouponService;
import com.suning.sawp.intf.promotion.CityTransService;
import com.suning.sawp.intf.storeman.StoreManService;
import com.suning.sawp.po.exchange.ExchangeCouponRecord;
import com.suning.sawp.po.exchange.ExchangeOrder;
import com.suning.sawp.service.util.AESUtils;
import com.suning.sawp.service.util.BeanUtil;
import com.suning.sawp.service.util.BigDecimalUtils;
import com.suning.sawp.service.util.ConfigUtil;
import com.suning.sawp.service.util.DateUtils;
import com.suning.sawp.service.util.RedisCacheUtils;
import com.suning.sawp.service.util.StringParamUtils;
import com.suning.sawp.vo.exchange.ActivityInfoVo;
import com.suning.sawp.vo.exchange.CouponRecordVo;
import com.suning.sawp.vo.exchange.ExchangeOrderVo;

/**
 * 〈以旧换新 发券相关service 实现类〉<br>
 *
 * @author 15030469 胡丹
 */
@Service("exchangeOrderSendCouponService")
public class ExchangeOrderSendCouponServiceImpl implements ExchangeOrderSendCouponService {
    private static final Logger LOGGER = LoggerFactory.getLogger(ExchangeOrderSendCouponServiceImpl.class);

    @Autowired
    RedisCacheUtils cacheUtils;
    @Autowired
    MemberInfoService memberInfoService;
    @Autowired
    private StoreManService storeManService;
    @Autowired
    private CityTransService cityTransService;
    @Autowired
    private ExchangeOrderDao exchangeOrderDao;
    @Autowired
    private ExchangeCouponRecordDao exchangeCouponRecordDao;
    @Reference(contractName = "", implCode = "freeCouponReceive")
    private FreeCouponReceiveReqService freeCouponReceiveReqService;
    private CouponRuleQueryEsbService couponRuleQueryEsbService;

    private SecureRandom secureRandom = new SecureRandom();

    @EsbEIHttpWired
    public void setCouponRuleQueryEsbService(CouponRuleQueryEsbService couponRuleQueryEsbService) {
        this.couponRuleQueryEsbService = couponRuleQueryEsbService;
    }

    @Autowired
    private ExchangeOrderCouponListQueryService jugdeCanJoinService;

    @Override
    public ReturnMsg<CouponDetailInfoDto> queryCouponDetailInfo(String employeeId, String activityId,
            String activitySecretKey) {
        if (StringParamUtils.checkIsEmpty(employeeId, activityId, activitySecretKey)) {
            throw new SawpException("查询券详情失败，参数不能为空");
        }

        // 根据员工工号取员工信息
        StoreManDto storeMan = storeManService.queryStoreManAttachInfo(employeeId);
        if (null == storeMan) {
            throw new SawpException("查询券详情失败，员工工号不正确");
        }

        ActivityInfoVo acticityInfo = new Gson().fromJson(
                cacheUtils.get(String.format(CacheKeyConstants.EXCHANGE_ACTIVITY_INFO, activityId)),
                new TypeToken<ActivityInfoVo>() {
                }.getType());
        if (null == acticityInfo) {
            throw new SawpException("查询券详情失败，活动编号获取终端信息等出错");
        }

        FreeCouponReceiveInputDto inputDto = new FreeCouponReceiveInputDto();
        inputDto.setCaller(ExchangeConstants.CALLER);
        inputDto.setOperateType(ExchangeConstants.OP_TYPE_QUERY);
        inputDto.setTerminalId(acticityInfo.getChannelId());
        inputDto.setBonusTrigerId(ExchangeConstants.BONUS_TRIGER_ID);

        inputDto.setChannelId(ExchangeConstants.CHANNEL_ID);
        inputDto.setCityId(StringUtils.leftPad(cityTransService.getMdmCityCodeFromPosCityCode(storeMan.getCityCode()),
                ExchangeConstants.COUPON_CENTER_CITY_LEN, "0"));
        inputDto.setStoreCode(storeMan.getStoreCode());
        inputDto.setCompanyCode(storeMan.getBranchCode());
        inputDto.setPayDate(DateUtils.getDateStrByFormat(new Date(), DateUtils.DEFAULT_TIME_PATTERN));

        inputDto.setActivityId(activityId);
        inputDto.setActivitySecretKey(activitySecretKey);

        LocateMemberInfo memberInfo = memberInfoService
                .locateMemberByMobileNo(ConfigConstants.INNER_COUPON_DEFAULT_MOBILE);
        String custNo = memberInfo != null ? memberInfo.getCustNum() : StringUtils.EMPTY;
        inputDto.setMemberId(custNo);

        FreeCouponReceiveOutputDto outputDto = null;
        try {
            outputDto = freeCouponReceiveReqService.receiveFreeCoupon(inputDto);

            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("免费领券接口查询 【{}】，返回【{}】", inputDto.toString(), outputDto.toString());
            }
        } catch (Exception e) {
            LOGGER.error("免费领券接口 异常，券id【{}】", activityId, e);
        }

        if ((null == outputDto
                || StringUtils.equals(ExchangeConstants.SEND_COUPON_RESULT_FALE, outputDto.getResultFlag()))) {
            LOGGER.info("免费领券接口【{}】", null == outputDto ? "null" : outputDto.toString());
            throw new SawpException("没有查询到对应的券详情");
        }

        CouponRuleQueryReq couponRuleQueryReq = new CouponRuleQueryReq();
        couponRuleQueryReq.setCouponRulesId(outputDto.getCouponRuleCode());
        couponRuleQueryReq.setSourceSystem(PromotionConstants.SYS_CODE_SNSAWP);
        couponRuleQueryReq.setPartScopeQuantityLimitNumber(ConfigUtil.getConfig(ConfigConstants.SAWP_CONFIG_PATH,
                ConfigConstants.PRO_COUPON_RULE_QUERY_LIMIT, ConfigConstants.DEFAULT_COUPON_RULE_LIMIT));
        MbfResponse resp = null;
        QueryCouponDetailInfoFromSPESEsbDto queryResultFromEsb = null;
        try {
            resp = couponRuleQueryEsbService.queryCouponRule(couponRuleQueryReq);
        } catch (Exception e) {
            LOGGER.error("促销中心查询券规则详情接口异常,券Id:【{}】", activityId, e);
        }

        if (null != resp && null != resp.getOutput()) {
            queryResultFromEsb = (QueryCouponDetailInfoFromSPESEsbDto) resp.getOutput()
                    .getMbfBody(QueryCouponDetailInfoFromSPESEsbDto.class);

            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("促销中心查询券规则详情接口查询 条件【{}】，返回【{}】", couponRuleQueryReq.toString(),
                        queryResultFromEsb.toString());
            }
        }

        CouponDetailInfoDto result = new CouponDetailInfoDto();
        // 如果都返回消息，并且标志位都是成功，则组装成功报文
        if (null != queryResultFromEsb && StringUtils.equals(ExchangeConstants.SEND_COUPON_RESULT_SUCCESS,
                queryResultFromEsb.getQueryResult())) {

            result.setCouponAmount(outputDto.getCouponAmount());
            result.setCouponType(ExchangeConstants.CouponType.getName(outputDto.getCouponType()));
            result.setShopName("苏宁");
            if (StringParamUtils.checkIsNotEmpty(queryResultFromEsb.getStartTime())
                    && StringParamUtils.checkIsNotEmpty(queryResultFromEsb.getEndTime())) {
                result.setInvalidTime(
                        String.format("%s 至 %s", StringParamUtils.subString(queryResultFromEsb.getStartTime(), 0, 10),
                                StringParamUtils.subString(queryResultFromEsb.getEndTime(), 0, 10)));
            } else {
                result.setInvalidTime("不限");
            }

            // 券名称也从缓存中取。因为接口里没有
            result.setCouponName(StringUtils.isEmpty(acticityInfo.getActivityName()) ? outputDto.getCouponName()
                    : acticityInfo.getActivityName());

            result.setUseRule(
                    StringUtils.equals(ExchangeConstants.COUPON_NUM_ONE, queryResultFromEsb.getCouponNum()) ? "单笔订单使用一张"
                            : StringUtils.equals(ExchangeConstants.COUPON_NUM_MORE, queryResultFromEsb.getCouponNum())
                                    ? "不限" : StringUtils.EMPTY);

            if (CollectionUtils.isNotEmpty(queryResultFromEsb.getCityList())) {
                List<String> areaLimitStrs = Lists.transform(queryResultFromEsb.getCityList(),
                        new Function<QueryCouponDetailInfoFromSPESEsbDto.CityDetail, String>() {
                            @Override
                            public String apply(QueryCouponDetailInfoFromSPESEsbDto.CityDetail input) {
                                return input.getCityName();
                            }
                        });
                result.setAreaLimit(StringUtils.join(areaLimitStrs, ExchangeConstants.SPLIT_LIST));
            } else {
                result.setAreaLimit("全国");
            }

            if (CollectionUtils.isNotEmpty(queryResultFromEsb.getNoMarketNameList())) {
                List<String> noMarketNameStrs = Lists.transform(queryResultFromEsb.getNoMarketNameList(),
                        new Function<QueryCouponDetailInfoFromSPESEsbDto.NoMarketNameDetail, String>() {
                            @Override
                            public String apply(QueryCouponDetailInfoFromSPESEsbDto.NoMarketNameDetail input) {
                                return input.getNoMarketName();
                            }
                        });

                result.setMarketLimit(StringUtils.join(noMarketNameStrs, ExchangeConstants.SPLIT_LIST));
            }

            result.setRewardsPreferential(queryResultFromEsb.getRewardsPreferential());

            if (CollectionUtils.isNotEmpty(queryResultFromEsb.getCouponRulesTerminalList())) {
                List<String> couponRulesTerminalStrs = Lists.transform(queryResultFromEsb.getCouponRulesTerminalList(),
                        new Function<QueryCouponDetailInfoFromSPESEsbDto.CouponRulesTerminalDetail, String>() {
                            @Override
                            public String apply(QueryCouponDetailInfoFromSPESEsbDto.CouponRulesTerminalDetail input) {
                                return input.getCouponRulesTerminalName();
                            }
                        });
                result.setCouponRulesTerminal(StringUtils.join(couponRulesTerminalStrs, ExchangeConstants.SPLIT_LIST));
            }

            result.setCouponRulesShowMsg(queryResultFromEsb.getCouponRulesShowMsg());
        } else {
            LOGGER.info("免费领券接口【{}】，券详情接口【{}】", outputDto.toString(),
                    null == queryResultFromEsb ? "null" : queryResultFromEsb.toString());
            throw new SawpException("没有查询到对应的券详情");
        }
        return new ReturnMsg<CouponDetailInfoDto>(result);
    }

    @Override
    @Transactional
    public ReturnMsg<String> sendCoupon(String employeeId, String mobileNo, String orderNo, String activityId,
            String activitySecretKey) {
        if (StringParamUtils.checkIsEmpty(mobileNo, orderNo, activityId, activitySecretKey)) {
            throw new SawpException("发券失败，参数不能为空");
        }

        String mobile = AESUtils.decodeAndDecrypt(mobileNo, ConfigConstants.AES_KEY);
        if (StringUtils.isEmpty(mobile)) {
            throw new SawpException("发券失败，手机号码解密失败");
        }

        // 根据员工工号取员工信息
        StoreManDto storeMan = storeManService.queryStoreManAttachInfo(employeeId);
        if (null == storeMan) {
            throw new SawpException("查询券详情失败，员工工号不正确");
        }

        String orderKey = String.format(CacheKeyConstants.EXCHANGE_MOBILE_ORDER, mobile);
        boolean orderExist = cacheUtils.sismember(orderKey, orderNo);
        if (!orderExist) {
            throw new SawpException("发券失败，请先根据手机号查询到对应的订单");
        }

        String activityKey = String.format(CacheKeyConstants.EXCHANGE_ORDER_ACTIVITY, orderNo);
        boolean activityExist = cacheUtils.sismember(activityKey, activityId);
        if (!activityExist) {
            throw new SawpException("发券失败，请先根据订单号选择到对应的券");
        }

        String key = String.format(CacheKeyConstants.EXCHANGE_ORDER_INFO, orderNo);
        String orderInfoStr = cacheUtils.get(key);
        if (StringUtils.isEmpty(orderInfoStr)) {
            throw new SawpException("发券失败，请先根据手机号查询到对应的订单");
        }
        ExchangeOrderVo orderInfo = new Gson().fromJson(orderInfoStr, new TypeToken<ExchangeOrderVo>() {
        }.getType());

        ActivityInfoVo acticityInfo = new Gson().fromJson(
                cacheUtils.get(String.format(CacheKeyConstants.EXCHANGE_ACTIVITY_INFO, activityId)),
                new TypeToken<ActivityInfoVo>() {
                }.getType());
        if (null == acticityInfo) {
            throw new SawpException("查询券详情失败，活动编号获取终端信息等出错");
        }

        boolean isCanJoin = isCanJoinActivity(activityId, orderInfo);
        if (!isCanJoin) {
            throw new SawpException("发券失败，当前订单已经不能参与该发券活动，请重新获取发券列表");
        }

        FreeCouponReceiveInputDto inputDto = new FreeCouponReceiveInputDto();
        inputDto.setCaller(ExchangeConstants.CALLER);
        inputDto.setOperateType(ExchangeConstants.OP_TYPE_SEND);
        inputDto.setTerminalId(acticityInfo.getChannelId());
        inputDto.setBonusTrigerId(ExchangeConstants.BONUS_TRIGER_ID);

        inputDto.setChannelId(ExchangeConstants.CHANNEL_ID);
        // 免费领券接口的orderId，必须要是不超过20位不重复的随机数
        String randomOrderId = StringUtils
                .substring(System.currentTimeMillis() + StringUtils.EMPTY + Math.abs(secureRandom.nextInt()), 0, 20);
        inputDto.setOrderId(randomOrderId);

        inputDto.setPayDate(DateUtils.getDateStrByFormat(
                DateUtils.getDateByStr(orderInfo.getCreateTime(), DateUtils.ACCURATE_MINUTES_PATTERN),
                DateUtils.DEFAULT_TIME_PATTERN));

        inputDto.setActivityId(activityId);
        inputDto.setActivitySecretKey(activitySecretKey);

        if (StringParamUtils.checkIsEmpty(orderInfo.getCustNum())) {
            throw new SawpException("发券失败，没有找到订单对应的会员编号");
        }
        inputDto.setMemberId(orderInfo.getCustNum());

        inputDto.setCityId(StringUtils.leftPad(cityTransService.getMdmCityCodeFromPosCityCode(storeMan.getCityCode()),
                ExchangeConstants.COUPON_CENTER_CITY_LEN, "0"));
        inputDto.setStoreCode(storeMan.getStoreCode());
        inputDto.setCompanyCode(storeMan.getBranchCode());

        FreeCouponReceiveOutputDto outputDto;
        try {
            outputDto = freeCouponReceiveReqService.receiveFreeCoupon(inputDto);
        } catch (Exception e) {
            LOGGER.error("免费领券接口 异常，券id【{}】", activityId, e);
            throw new SawpException("发券失败，系统异常");
        }

        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("免费发券执行接口返回：【{}】", outputDto.toString());
        }

        if (null != outputDto
                && StringUtils.equals(ExchangeConstants.SEND_COUPON_RESULT_SUCCESS, outputDto.getResultFlag())) {
            ExchangeOrder exchangeOrder = exchangeOrderDao.selectOrder(orderNo);
            // 如果没有订单信息，则新增，否则只新增一条子表发券记录
            if (exchangeOrder == null) {
                exchangeOrder = new ExchangeOrder();
                exchangeOrder.setOrderNo(orderNo);
                exchangeOrder.setCmmdtyCode(orderInfo.getCmmdtyCode());
                int cmmdyNumValue;
                try {
                    cmmdyNumValue = Integer.parseInt(orderInfo.getCmmdtyNum());
                } catch (NumberFormatException e) {
                    LOGGER.error("sendCoupon orderInfo.getCmmdtyNum() 【{}】 format error  ", orderInfo.getCmmdtyNum(),
                            e);
                    cmmdyNumValue = 0;
                }
                exchangeOrder.setCmmdtyNum(cmmdyNumValue);
                exchangeOrder.setCmmdtyName(orderInfo.getCmmdtyName());
                exchangeOrder.setCmmdtyPic(orderInfo.getCmmdtyPic());
                exchangeOrder.setCreateTime(new Date());
                exchangeOrder.setMobileNo(mobile);
                exchangeOrder.setCustNum(orderInfo.getCustNum());
                exchangeOrder.setEvaluatePrice(new BigDecimal(orderInfo.getEvaluatePrice()));

                exchangeOrderDao.saveOrder(exchangeOrder);
            }

            ExchangeCouponRecord exchangeCouponRecord = new ExchangeCouponRecord();
            exchangeCouponRecord.setOrderNo(orderNo);
            // 把这个随机数记到数据库
            exchangeCouponRecord.setRandomValue(randomOrderId);
            exchangeCouponRecord.setSendTime(new Date());
            exchangeCouponRecord.setEmployeeId(employeeId);
            exchangeCouponRecord
                    .setCouponAmount(BigDecimalUtils.halfUpTwoDecimal(new BigDecimal(outputDto.getCouponAmount())));
            exchangeCouponRecord.setCouponStartTime(
                    DateUtils.getDateByStr(outputDto.getCouponStartTime(), DateUtils.DEFAULT_TIME_PATTERN));
            exchangeCouponRecord.setCouponEndTime(
                    DateUtils.getDateByStr(outputDto.getCouponEndTime(), DateUtils.DEFAULT_TIME_PATTERN));

            exchangeCouponRecord.setCouponType(
                    outputDto.getCouponType() + ExchangeConstants.CouponType.getName(outputDto.getCouponType()));

            exchangeCouponRecord.setCouponNo(outputDto.getCouponNo());
            exchangeCouponRecord.setCouponRuleCode(outputDto.getCouponRuleCode());

            exchangeCouponRecord.setCouponName(StringUtils.isEmpty(acticityInfo.getActivityName())
                    ? outputDto.getCouponName() : acticityInfo.getActivityName());

            exchangeCouponRecordDao.saveCouponRecord(exchangeCouponRecord);
            return new ReturnMsg<String>("发券成功");
        } else {
            LOGGER.info("免费发券接口发券结果【{}】", null == outputDto ? "null" : outputDto.toString());
            return new ReturnMsg<String>(ReturnMsg.FAIL, null == outputDto ? "发券失败" : outputDto.getFailMessage());
        }

    }

    @Override
    public ReturnMsg<SendCouponRecordDto> querySendCouponRecord(String employeeId, Integer pageNo) {
        if (StringParamUtils.checkIsEmpty(employeeId)) {
            throw new SawpException("员工工号不能为空");
        }

        int pageNoCheck = pageNo < 1 ? 0 : pageNo;// pageNo必须>-1
        int startRow = ExchangeConstants.PAGE_SIZE * (pageNoCheck - 1);

        int totalCount = exchangeCouponRecordDao.countTotal(employeeId);
        List<CouponRecordVo> recordList = exchangeCouponRecordDao.filterCouponRecord(employeeId, startRow,
                ExchangeConstants.PAGE_SIZE);

        SendCouponRecordDto result = new SendCouponRecordDto();
        result.setTotalCouponNum(totalCount);

        if (CollectionUtils.isNotEmpty(recordList)) {
            result.setCouponList(Lists.transform(recordList, new Function<CouponRecordVo, CouponRecordDto>() {
                @Override
                public CouponRecordDto apply(CouponRecordVo input) {
                    CouponRecordDto out = new CouponRecordDto();
                    BeanUtil.copyProperties(out, input);
                    out.setMobileNo(StringParamUtils.desensitizeMobilePhone(out.getMobileNo()));
                    return out;
                }
            }));
        }
        return new ReturnMsg<SendCouponRecordDto>(result);
    }

    /**
     * 
     * 功能描述: 判断订单是否还可以参加该活动，可能会存在进入列表页时参加活动，但是进入后规则发生变化，但页面不刷新的情况<br>
     * 
     * @param activityId
     * @param order
     * @return
     */
    private boolean isCanJoinActivity(String activityId, ExchangeOrderVo order) {
        List<ActivityDetail> configActivity = new ArrayList<ActivityDetail>();
        ActivityDetail activity = new ActivityDetail();
        activity.setActivityId(activityId);
        configActivity.add(activity);

        List<ActivityDetail> canJoinActivityList = jugdeCanJoinService.getCanJoinActivity(configActivity, order);
        if (!CollectionUtils.isEmpty(canJoinActivityList)
                && StringUtils.equals(activityId, canJoinActivityList.get(0).getActivityId())) {
            return true;
        } else {
            return false;
        }
    }
}
